package cn.agiledata.bank.linkbank.impl.ccb;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import CCBSign.RSASig;

import cn.agiledata.bank.common.util.IOUtil;
import cn.agiledata.bank.common.util.MD5;
import cn.agiledata.bank.linkbank.exception.LinkBankException;

/**
 * 中国建设银行通用方法类
 * 
 * @author 马贤波
 * 
 */
class CcbUtils {
    private CcbUtils() {
    }

    /**
     * 按照建设银行生成数字签名的规则拼凑加密明文
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @return 拼凑好的加密明文
     */
    private static String getScrabbleContent(Map values, String[] keys) {
        String content = "";
        for (int i = 0; i < keys.length; i++) {
            content += keys[i] + "=" + values.get(keys[i]) + "&";
        }
        if (content.length() > 0) {
            content = content.substring(0, content.length() - 1);
        }
        return content;
    }

    /**
     * 按照建设银行生成数字签名的规则生成数字签名
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @return 生成的数字签名
     */
    public static String generateMac(Map values, String[] keys) {
        String scrabbleContent = getScrabbleContent(values, keys);
        return (new MD5()).getMD5ofStr(scrabbleContent).toLowerCase();
    }

    /**
     * 根据指定公钥文件路径获取公钥内容
     * 
     * @param pulicKeyFilePath
     *            公钥文件路径
     * @return 公钥内容
     * @throws IOException
     */
    private static String getPublicKey(String pulicKeyFilePath)
            throws IOException {
        pulicKeyFilePath = IOUtil.getAbsolutePath(pulicKeyFilePath);
        InputStream in = new FileInputStream(pulicKeyFilePath);
        byte[] fileContent = new byte[in.available()];
        in.read(fileContent);
        in.close();
        return new String(fileContent);
    }

    /**
     * 按照建设银行生成数字签名的规则校验数字签名
     * 
     * @param values
     *            所有参数
     * @param keys
     *            参与校验的顺序相关的关键字组
     * @param digitalSign
     *            作为比较根据的数字签名
     * @param publicKeyFilePath
     *            公钥文件路径
     * @return true if 校验通过, otherwise false
     * @throws LinkBankException
     */
    public static boolean validateDigitalSign(Map values, String[] keys,
            String digitalSign, String publicKeyFilePath)
            throws LinkBankException {
        try {
            String publicKey = getPublicKey(publicKeyFilePath);
            RSASig sign = new RSASig();
            sign.setPublicKey(publicKey);
            String content = getScrabbleContent(values, keys);
            return sign.verifySigature(digitalSign, content);
        } catch (IOException e) {
            throw LinkBankException.CANNOT_LOAD_CERT;
        }
    }
}
